package com.sjgtw.cloud.auth.service;

import com.sjgtw.cloud.client.entity.UserInfo;
import com.sjgtw.cloud.client.oauth.OauthClientConfig;
import com.sjgtw.cloud.common.core.constant.Constants;
import com.sjgtw.cloud.common.core.constant.UserConstants;
import com.sjgtw.cloud.common.core.domain.R;
import com.sjgtw.cloud.common.core.enums.UserStatus;
import com.sjgtw.cloud.common.core.exception.BaseException;
import com.sjgtw.cloud.common.core.exception.CustomException;
import com.sjgtw.cloud.common.core.utils.SecurityUtils;
import com.sjgtw.cloud.common.core.utils.ServletUtils;
import com.sjgtw.cloud.common.core.utils.StringUtils;
import com.sjgtw.cloud.common.core.utils.encrypt.RSAUtils;
import com.sjgtw.cloud.common.redis.service.RedisService;
import com.sjgtw.cloud.system.api.domain.SysUser;
import com.sjgtw.cloud.system.api.model.LoginUser;
import com.sjgtw.cloud.system.api.service.RemoteConfigService;
import com.sjgtw.cloud.system.api.service.RemoteLogService;
import com.sjgtw.cloud.system.api.service.RemoteUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * <p>Title: 登录校验方法</p>
 * <p>Description: </p>
 * @author Admin
 * @date 2020-7-8
 */
@Component
public class SysLoginService 
{
    public static void main(String[] args) {
        try {
            String s = RSAUtils.priKeyDecrypt("lW4OZjvGZlZvfYE7I2QyLumPmsuzSQxZVDAh6hIcI2BmeZTyXzh+t3AVpCc45RoqAsJUjI3sGon9mWi8zY4JENfDtthBIiGJfrV2XlyVR4uH2FXg/G1ZnRdNKaMTpBjMzTtmTphtYs6SNkx63MBk1pJnrqcgJXlpvn2paB0sR/c=", RSAUtils.priKey, null);


            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Autowired
    private RemoteLogService remoteLogService;

    @Autowired
    private RemoteUserService remoteUserService;
    
    @Autowired
	private RedisService redisService;

    @Autowired
    OauthClientConfig oauthClientConfig;

    @Autowired
    private RemoteConfigService remoteConfigService;
  
    /**
     * <p>Title: 用户登录</p>
     * <p>Description: 登录页面登录 </p>
     * @param username
     * @param password
     * @return
     */
    public LoginUser login(String username, String password)
    {
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, password))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户/密码不能为空(登录页面登录)");
            throw new BaseException("用户或密码不能为空！");
        }
        //RSA解密
        try {
			password = RSAUtils.priKeyDecrypt(password, RSAUtils.priKey, null);
		} catch (Exception e) {
			throw new BaseException("请检验您的账号或密码是否输入正确！");
		}
        
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围(登录页面登录)");
            throw new BaseException("请检验您的账号或密码是否输入正确！");
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围(登录页面登录)");
            throw new BaseException("请检验您的账号或密码是否输入正确！");
        }
        
        // 查询用户信息
        R<LoginUser> userResult = remoteUserService.getUserInfo(username);

        if (R.FAIL == userResult.getCode())
        {
            //throw new BaseException(userResult.getMsg());
            throw new BaseException("请检验您的账号或密码是否输入正确！");
        }

        if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在(登录页面登录)");
            throw new BaseException("请检验您的账号或密码是否输入正确！");
            
        }
        LoginUser userInfo = userResult.getData();
        SysUser user = userResult.getData().getSysUser();
        if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "您的账号已被注销(登录页面登录)");
            throw new BaseException("您的账号：" + username + " 已被注销！");
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "您的账号已被锁定或停用(登录页面登录)");
           throw new BaseException("您的账号：" + username + " 已被锁定或停用！");
        }
    	
        //密码RSA处理:AT-JDR
        if (!SecurityUtils.matchesPassword(password, user.getPassword()))
        {
            // 获取参数配置中默认的密码错误次数的值
            R<String> configByKey = remoteConfigService.getConfigByKey("sys.auth.signFrequency");
//            System.out.printf("*****************>>  " + configByKey.getData());
            int sysSignFrequency = StringUtils.isNull(configByKey) ? 5 : Integer.valueOf(String.valueOf(StringUtils.isNotEmpty(configByKey.getData())?configByKey.getData():0));
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码错误(登录页面登录)");
      	    //30分钟内密码错误一定次数锁定用户
        	Integer signFrequency = redisService.getCacheObject(Constants.SYS_SIGNIN_LOCK_KEY + username);
        	if(StringUtils.isNull(signFrequency)) {signFrequency = 0;}
        	 ++signFrequency;
        	if(signFrequency < sysSignFrequency)  //计数
        	{
              redisService.setCacheObject(Constants.SYS_SIGNIN_LOCK_KEY + username, signFrequency, 30L, TimeUnit.MINUTES);
              throw new BaseException("请检验您的账号或密码是否输入正确 ，您还有【"+(sysSignFrequency - signFrequency)+"】次尝试机会！");
        	}
        	else  //锁用户
        	{
        	    R<Integer> luType = remoteUserService.lockUserStatus(user.getUserId());
                if (StringUtils.isNotNull(luType) && R.FAIL != luType.getCode()
                		&& StringUtils.isNotNull(luType.getData()) && luType.getData() > 0)
                {
                	 // 物理锁定用户成功并释放缓用户存锁
                    redisService.deleteObject(Constants.SYS_SIGNIN_LOCK_KEY + username);
                }
                throw new BaseException("您的输入错误次数已经达到上限，账户已锁定，请联系管理员！");
        	}
        }
        remoteLogService.saveLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功(登录页面登录)");
        // 登录成功释放缓用户存锁
        redisService.deleteObject(Constants.SYS_SIGNIN_LOCK_KEY + username);
        return userInfo;
    }

    public void logout(String loginName)
    {
        remoteLogService.saveLogininfor(loginName, Constants.LOGOUT, "退出成功");
    }

    /**
     * <p>Title: 单点登录</p>
     * <p>Description: Oauth2.0</p>
     * @param callbackUser
     * @return
     */
    public LoginUser callback(UserInfo callbackUser)
    {
        String username = callbackUser.getUsername();
        if (StringUtils.isEmpty(username))
        {
            throw new CustomException(oauthClientConfig.getErrorEndpoint()+"?errcode=LoginErr-004&msg="+ ServletUtils.urlEncode("无法获取登录用户"),302);
        }
        // 查询用户信息
        R<LoginUser> userResult = remoteUserService.getUserInfo(username);

        if (R.FAIL == userResult.getCode())
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, userResult.getMsg().concat("(SSO登录)"));
            throw new CustomException(oauthClientConfig.getErrorEndpoint()+"?errcode=LoginErr-002&msg="+ServletUtils.urlEncode("系统内部无此用户"),302);
        }
        //用户不存在情况
        if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在(SSO登录)");
            throw new CustomException(oauthClientConfig.getErrorEndpoint()+"?errcode=LoginErr-002&msg="+ServletUtils.urlEncode("系统内部无此用户"),302);
        }

        LoginUser userInfo = userResult.getData();
        SysUser user = userResult.getData().getSysUser();
        if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户已被删除(SSO登录)");
            throw new CustomException(oauthClientConfig.getErrorEndpoint()+"?errcode=LoginErr-002&msg="+ServletUtils.urlEncode("系统内部无此用户"),302);
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户已被禁用(SSO登录)");
            throw new CustomException(oauthClientConfig.getErrorEndpoint()+"?errcode=LoginErr-003&msg="+ServletUtils.urlEncode("用户已被禁用"),302);
        }
        remoteLogService.saveLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功(SSO登录)");
        return userInfo;
    }
}